package com.haredot.filter;

import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.haredot.entity.User;
import com.haredot.handler.TokenContextHolder;
import com.haredot.result.R;
import com.haredot.utils.JwtUtils;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.List;

public class BearTokenAuthenticationFilter extends OncePerRequestFilter {

    private static final List<String> ALLOW_URLS = List.of("/api/token", "/register", "/student/qrcode/detail", "/manager/confirm") ;
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // 获取 请求 URL
        String servletPath = request.getServletPath();

        if (ALLOW_URLS.contains(servletPath) || "OPTIONS".equals(request.getMethod())) {
            filterChain.doFilter(request, response);
            return ;
        }

        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Headers", "*");
        response.setHeader("Access-Control-Allow-Methods",  "*");

        // 如果 请求地址不包含、则  必须 添加 权限认证
        String authentication = request.getHeader("authorization");

        if (authentication == null || !authentication.startsWith("Bearer ")) {
            // 提示错误信息、认证失败
            R<?> build = R.fail(R.StatusCode.FORBIDDEN).build();
            MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
            converter.write(build, MediaType.APPLICATION_JSON, new ServletServerHttpResponse(response));
            return ;
        }

        // 如果 有 Bearer , 获取 令牌
        String token = authentication.substring(7);

        try {
            // 验证令牌
            DecodedJWT decodedJWT = JwtUtils.checkToken(token);

            // 判断 该令牌是否是 访问令牌
            String id = decodedJWT.getId();
            String text = new String(Base64.getDecoder().decode(id), StandardCharsets.UTF_8);

            if (text.split(":").length != 3) {
                R<?> build = R.fail(R.StatusCode.FORBIDDEN, "令牌格式不正确").build();
                MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
                converter.write(build, MediaType.APPLICATION_JSON, new ServletServerHttpResponse(response));
                return ;
            }

            // 将当前登录的用户信息写入到 ThreadLocal 中
            User user = new User();
            user.setId(Long.parseLong(decodedJWT.getSubject()));
            user.setName(decodedJWT.getClaim("name").asString());
            TokenContextHolder.setAuthenticationUser(user);
            // 继续访问 请求
            filterChain.doFilter(request, response);

        }catch (TokenExpiredException e) {
            response.setStatus(418);
            R<?> build = R.fail(R.StatusCode.FORBIDDEN, "令牌失效").build();
            MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
            converter.write(build, MediaType.APPLICATION_JSON, new ServletServerHttpResponse(response));
        }catch (Exception e) {
            e.printStackTrace();
            R<?> build = R.fail(R.StatusCode.FORBIDDEN, "令牌不正确").build();
            MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
            converter.write(build, MediaType.APPLICATION_JSON, new ServletServerHttpResponse(response));
        }finally {
            TokenContextHolder.clear();
        }
    }
}
